package net.atomarrow.ioc;

import net.atomarrow.annotation.Inject;
import net.atomarrow.annotation.NoInject;
import net.atomarrow.aop.InterceptorKeeper;
import net.atomarrow.controllers.Controller;
import net.atomarrow.inits.InitLoader;
import net.atomarrow.services.Service;
import net.atomarrow.services.ServiceProxy;

import java.lang.reflect.Field;
import java.util.HashMap;
/**
 * Ioc容器
 * @author Michael
 *
 */
public class ApplicationContext {

    private static HashMap<Class, Object> beans = new HashMap<Class, Object>();

    public static void inject(Object object) {
        injectParent(object,object.getClass());
        injectField(object,object.getClass().getDeclaredFields());
    }

    private static void injectField(Object object,Field[] fields) {
        Object bean;
        Class clazz;
        try {
            for (Field field : fields) {
                clazz=field.getType();
                if(!needInject(field,clazz)){
                    continue;
                }
                field.setAccessible(true);
                bean = get(clazz);
                if (bean != null) {
                    field.set(object, bean);
                }else{
                    load(clazz.newInstance());
                    bean = get(clazz);
                    field.set(object, bean);
                }
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    private static void injectParent(Object object,Class currentClass) {
        Class parentClass = currentClass.getSuperclass();
        if(parentClass!=null&&parentClass!=Object.class&&!parentClass.isInterface()){
            injectField(object,parentClass.getDeclaredFields());
            injectParent(object, parentClass);
        }
    }
    
    private static boolean needInject(Field field, Class clazz) {
        if(field.isAnnotationPresent(NoInject.class)){
            return false;
        }
        if(Controller.class.isAssignableFrom(clazz)){
            return true;
        }
        if(Service.class.isAssignableFrom(clazz)){
            return true;
        }
        if(InitLoader.class.isAssignableFrom(clazz)){
            return true;
        }
        return field.isAnnotationPresent(Inject.class);
    }
    


    public static void load(Object object) {
    	load(object.getClass(), object);
    }
    
    public static void load(Class key,Object object) {
    	if(object instanceof Service){
    		object =getServiceProxy(object);
    	}
    	beans.put(key, object);
        inject(object);
    }

    private static Object getServiceProxy(Object object) {
    	if(!get(InterceptorKeeper.class).hasServiceInterceptor()){
    		return object;
    	}
    	ServiceProxy proxy = new ServiceProxy();
    	inject(proxy);
		return proxy.getProxy(object);
	}

	public static <T> T get(Class<T> clazz) {
		T t= (T) beans.get(clazz);

		if(t==null){
		    //加锁，防止多个线程同时实例化同一个类的对象
		    synchronized (clazz) {
		        if ((t = (T) beans.get(clazz)) == null) {
                    //可能是类还没有加载
                    try {
                        load(clazz.newInstance());
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    t=(T) beans.get(clazz);
                }


            }
		}
        return t;
    }
    
	public static void remove(Class clazz){
		beans.remove(clazz);
	}
}
